﻿using Core.DataAccess.Model;
using Core.Framework;
using Dapper;
using Grain.Interfaces;
using iTool.ClusterComponent;
using Orleans.Concurrency;
using System;
using System.Threading.Tasks;

namespace Grain.Implements
{
    [StatelessWorker(500)]
    [Reentrant]
    public class CloudRunningFunctionService : iToolServiceStorageBase<Function>, ICloudRunningFunctionService
    {
        private CloudRunningFunctionExtend extend;
        private IDBFactory iDBFactory;

        public CloudRunningFunctionService(IDBFactory iDBFactory)
        {
            this.iDBFactory = iDBFactory;
        }

        public async override Task OnActivateAsync()
        {
            this.extend = new CloudRunningFunctionExtend(this.GrainFactory);
            await base.OnActivateAsync();
        }

        public Task<string> GetFunctionModulePath()
        {
            return Task.FromResult(this.State.modulePath);
        }

        public async Task<FunctionResult<dynamic>> Invoke(string channel, params object[] parameters)
        {

            TimeSpan ts1 = new TimeSpan(DateTime.Now.Ticks);

            bool isHavChannel = !string.IsNullOrWhiteSpace(channel);

            object[] args = isHavChannel
                ? await this.extend.GetFunctionParametersAsync(channel, parameters)
                : this.extend.GetFunctionParameters(parameters);

            // 调用指定函数
            var resultJS = await NodeJS.InvokeAsync<dynamic>(this.State.modulePath, args);

            FunctionResult<dynamic> result = this.extend.GetFunctionResult(
                ts1,
                args[0] as SystemObject,
                resultJS);

            await this.extend.InvokeEndAsync(isHavChannel, channel, result);

            return result;
        }

        public async Task<FunctionResult<dynamic>> InvokeExport(string channel, string exportedFunctionName, params object[] parameters)
        {
            TimeSpan ts1 = new TimeSpan(DateTime.Now.Ticks);

            bool isHavChannel = !string.IsNullOrWhiteSpace(channel);

            object[] args = isHavChannel
                ? await this.extend.GetFunctionParametersAsync(channel, parameters)
                : this.extend.GetFunctionParameters(parameters);

            // 调用指定函数
            var resultJS = await NodeJS.InvokeExportAsync<dynamic>(this.State.modulePath, exportedFunctionName, args);

            FunctionResult<dynamic> result = this.extend.GetFunctionResult(
                ts1,
                args[0] as SystemObject,
                resultJS);

            await this.extend.InvokeEndAsync(isHavChannel, channel, result);

            return result;
        }

        protected override Task ClearStateAsync()
        {
            using (var db = this.iDBFactory.Create(DatabaseType.Function))
            {
                var result = db.Execute($"delete [Function] where id = {this.State.id}");
            }
            return Task.CompletedTask;
        }

        protected override Task ReadStateAsync()
        {
            string moduleName = this.GetStringKey();

            using (var db = this.iDBFactory.Create(DatabaseType.Function))
            {
                this.State = db.QueryFirstOrDefault<Function>($"select id,moduleName,modulePath,scriptContent from [Function] where moduleName = @moduleName", new { moduleName });
            }

            this.State.modulePath = this.State.modulePath + "_module";
            return Task.CompletedTask;
        }

        protected override Task WriteStateAsync()
        {

            using (var db = this.iDBFactory.Create(DatabaseType.Function))
            {
                var result = db.Execute($"update [Function] set scriptContent=@script where id = @id", new
                {
                    id = this.State.id,
                    script = this.State.scriptContent
                });
            }

            return Task.CompletedTask;
        }
    }

}
